﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

using System.Collections.Generic;
using ScrumTable.Common.Collections;

namespace ScrumTable.Common.Text
{
    #region Usings

    using System;
    using System.Text;
    using System.Collections;

    #endregion

    /// <summary>
    /// Contains the global utilities for the string class.
    /// </summary>
    public static class StringUtil
    {
        #region Methods

        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Returns true if the given text starts with a number.
        /// </summary>
        /// <param name="text">Specifies the string this pointer.</param>
        public static bool StartsWithNumber(this string text)
        {
            PreCondition.AssertNotNull(text, "text");

            return (text[0] >= 0x30 && text[0] <= 0x39);
        }

        /// <summary>
        /// Shrink to string to a given length.
        /// </summary>
        /// <param name="text">Specifies the string this pointer.</param>
        /// <param name="length">Specifies the length to shrink.</param>
        /// <returns>Returns the shrinked version of the text.</returns>
        public static string ShrinkText(this string text, int length=20)
        {
            PreCondition.AssertNotNull(text, "text");

            if (text.Length > length)
            {
                return text.Substring(0, length / 2) + " ... " + text.Substring(text.Length - length / 2);
            }
            return text;
        }

        /// <summary>
        /// Concatenates a specified separator String between each element
        /// of a specified String array, yielding a single concatenated string.
        /// </summary>
        /// <param name="toJoin">Specifies the list of elements to join together.</param>
        /// <param name="separator">Specifies the list separator.</param>
        /// <returns>Returns the concatenated string.</returns>
        public static string Join(IEnumerable toJoin, string separator)
        {
            StringBuilder dataBuffer = new StringBuilder();

            foreach (object dataValue in toJoin)
            {
                if (dataBuffer.Length > 0)
                    dataBuffer.Append(separator);
                dataBuffer.Append(dataValue);
            }
            return dataBuffer.ToString();
        }

        /// <summary>
        /// Tries to parse the current string as an enumeration of the 
        /// given type.
        /// The implementation follows the Try-Parse pattern.
        /// </summary>
        /// <typeparam name="T">Type of the enumeration to convert.</typeparam>
        /// <param name="input">Specifies the current string instance.</param>
        /// <param name="data">Specifies the converted output (enum) data.</param>
        /// <returns>Returns true, if the value could be converted.</returns>
        public static bool TryParseEnum<T>(this string input, out T data)
            where T : struct
        {
            return EnumUtil.TryParse(input, out data);
        }

        /// <summary>
        /// Tries to parse the current string as an enumeration of the 
        /// given type.
        /// The implementation follows the Try-Parse pattern.
        /// </summary>
        /// <typeparam name="T">Type of the enumeration to convert.</typeparam>
        /// <param name="input">Specifies the current string instance.</param>
        /// <returns>Returns the converted value.</returns>
        public static T TryParseEnumOrDefault<T>(this string input)
            where T : struct
        {
            return input.TryParseEnumOrDefault(default(T));
        }

        /// <summary>
        /// Tries to parse the current string as an enumeration of the 
        /// given type.
        /// The implementation follows the Try-Parse pattern.
        /// </summary>
        /// <typeparam name="T">Type of the enumeration to convert.</typeparam>
        /// <param name="input">Specifies the current string instance.</param>
        /// <param name="defaultValue">Specifies the default value if the parse procedure fails.</param>
        /// <returns>Returns the converted value.</returns>
        public static T TryParseEnumOrDefault<T>(this string input, T defaultValue)
            where T : struct
        {
            T parsed;
            if (input.TryParseEnum(out parsed))
                return parsed;
            return defaultValue;
        }

        /// <summary>
        /// Removes the specified post fix from the current string and
        /// returns the new created string.
        /// </summary>
        /// <param name="input">Specifies the current string instance.</param>
        /// <param name="postfix">Postfix string to process.</param>
        /// <returns>Returns the new string without the given postfix.</returns>
        public static string TrimEnd(this string input, string postfix)
        {
            if (!input.EndsWith(postfix) || string.IsNullOrEmpty(postfix))
                return input;

            return input.Substring(0, input.Length - postfix.Length);
        }

        /// <summary>
        /// Cuts off a part of a string. The cut off window is specified with a
        /// start end end fragment.
        /// </summary>
        /// <param name="input">Specifies the current string instance.</param>
        /// <param name="start">Specifies the left window position, the first match is taken.</param>
        /// <param name="end">Specifies the right window position, the first match after the left window position is taken.</param>
        /// <returns>Returns the middle of the string window between the start and end point.</returns>
        public static string CutOff(this string input, string start, string end)
        {
            PreCondition.AssertNotNullOrEmpty(start, "start");
            PreCondition.AssertNotNullOrEmpty(end, "end");

            string endData = input;
            int dataBegin = input.IndexOf(start);

            if (dataBegin != -1)
            {
                dataBegin += start.Length;
                endData = endData.Substring(dataBegin, input.Length - dataBegin);
                int imageEnd = endData.IndexOf(end);

                if (imageEnd != -1)
                    endData = endData.Substring(0, imageEnd);
            }
            return endData;
        }

        /// <summary>
        /// Gets the left value if it is not null or empty. Otherwise the right
        /// value will be returned.
        /// </summary>
        /// <param name="left">Specifies the current string instance.</param>
        /// <param name="right">Specifies the left window position, the first match is taken.</param>
        /// <returns>Returns the middle of the string window between the start and end point.</returns>
        public static string GetLNotNull(string left, string right)
        {
            if (string.IsNullOrEmpty(left))
            {
                return (right ?? string.Empty);
            }
            return left;
        }

        /// <summary>
        /// Gets the string to validate with the given max length.
        /// </summary>
        /// <param name="toValidate">Specifies the string to validate and cut off.</param>
        /// <param name="length">Specifies the maximum length of the string to obtain.</param>
        /// <returns>Returns the evaluated string.</returns>
        public static string MaxLength(string toValidate, int length)
        {
            if (!string.IsNullOrEmpty(toValidate) && toValidate.Length > length)
            {
                return toValidate.Substring(0, length);
            }
            return toValidate;
        }

        /// <summary>
        /// Splits the given string and removes all whitespaces from the resulting elements.
        /// </summary>
        /// <param name="toSplit">Specifies the string to split.</param>
        /// <param name="separator">Specifies the split delimiter character.</param>
        public static IList<string> SplitTrim(this string toSplit, char separator)
        {
            string[] splitElements = (toSplit ?? string.Empty).Split(
                new[] { separator },
                StringSplitOptions.RemoveEmptyEntries);

            return splitElements.ConvertIf(
                elem => !string.IsNullOrWhiteSpace(elem),
                elem => elem.Trim());
        }

        #endregion
    }
}
